package com.dora.basic.juc;

import org.junit.jupiter.api.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.LockSupport;

/**
 * T1 t2 t3顺序运行
 *
 * @author hanchen
 * @date 2024/02/21
 */
public class T1T2T3OrderRun {

    /**
     * 随机运行
     */
    @Test
    public void randomRun() {
        Thread t1 = new Thread(() -> {
            System.out.println("我是t1任务");
        });

        Thread t2 = new Thread(() -> {
            System.out.println("我是t2任务");
        });

        Thread t3 = new Thread(() -> {
            System.out.println("我是t3任务");
        });
        t1.start();
        t2.start();
        t3.start();
    }

    /**
     * 使用Join方式顺序运行
     */
    @Test
    public void orderRunWithJoin() {
        Thread t1 = new Thread(() -> {
            System.out.println("我是t1任务");
        });

        Thread t2 = new Thread(() -> {
            try {
                t1.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("我是t2任务");
        });

        Thread t3 = new Thread(() -> {
            try {
                t2.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("我是t3任务");
        });
        t1.start();
        t2.start();
        t3.start();
    }

    /**
     * 使用CountDownLatch方式顺序执行
     */
    @Test
    public void orderRunWithCountDownLatch() {
        CountDownLatch latch1 = new CountDownLatch(1);
        CountDownLatch latch2 = new CountDownLatch(1);
        Thread t1 = new Thread(() -> {
            System.out.println("我是t1任务");
            latch1.countDown();
        });

        Thread t2 = new Thread(() -> {
            try {
                latch1.await();
                System.out.println("我是t2任务");
                latch2.countDown();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        Thread t3 = new Thread(() -> {
            try {
                latch2.await();
                System.out.println("我是t3任务");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }

    private static Thread t1;
    private static Thread t2;
    private static Thread t3;

    /**
     * 使用LockSupport方式顺序执行
     */
    @Test
    public void orderRunWithLockSupport() {
        t1 = new Thread(() -> {
            System.out.println("我是t1任务");
            LockSupport.unpark(t2);
        });

        t2 = new Thread(() -> {
            LockSupport.park();
            System.out.println("我是t2任务");
            LockSupport.unpark(t3);
        });
        t3 = new Thread(() -> {
            LockSupport.park();
            System.out.println("我是t3任务");
        });
        t1.start();
        t2.start();
        t3.start();
    }


    private static final Object lock = new Object();
    private static volatile int currentThread = 1;

    /**
     * Order run with wait
     */
    @Test
    public void orderRunWithWait() {
        Thread t1 = new Thread(() -> {
            runTask("我是t1任务", 1);
        });

        Thread t2 = new Thread(() -> {
            runTask("我是t2任务", 2);
        });

        Thread t3 = new Thread(() -> {
            runTask("我是t3任务", 3);
        });

        t1.start();
        t2.start();
        t3.start();
    }

    /**
     * 运行任务
     *
     * @param message        消息
     * @param expectedThread 预期线程
     */
    private void runTask(String message, int expectedThread) {
        synchronized (lock) {
            while (currentThread != expectedThread) {
                try {
                    // 当前线程等待，释放锁
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(message);
            // 切换到下一个线程
            currentThread = (currentThread % 3) + 1;
            lock.notifyAll(); // 唤醒所有等待线程
        }
    }
}
